package com.quanshu.exchange.ui.gui.message.chat.expand;

import android.media.AudioManager;
import android.media.RingtoneManager;
import android.media.SoundPool;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.baselibrary.util.glide.GlideUtils;
import com.hyphenate.chat.EMCallStateChangeListener;
import com.hyphenate.chat.EMClient;
import com.hyphenate.chat.EMVideoCallHelper;
import com.hyphenate.exceptions.HyphenateException;
import com.hyphenate.media.EMCallSurfaceView;
import com.quanshu.exchange.R;
import com.quanshu.exchange.support.api.UserInterface;
import com.quanshu.exchange.support.config.Config;
import com.quanshu.exchange.support.db.UserDao;
import com.quanshu.exchange.support.entity.UserEntity;
import com.quanshu.exchange.support.net.BaseResponse;
import com.quanshu.exchange.support.net.core.BaseObserver;
import com.quanshu.exchange.support.net.core.NetClient;
import com.quanshu.exchange.support.utils.AppUtils;
import com.quanshu.exchange.support.utils.ToastHelper;
import com.quanshu.exchange.ui.widget.MyChronometer;

import java.util.UUID;

import butterknife.BindView;
import butterknife.ButterKnife;

/**
 * Created by jye on 2018/2/28.
 */

public class VideoCallActivity extends CallActivity {

    @BindView(R.id.opposite_surface)
    EMCallSurfaceView oppositeSurface;
    @BindView(R.id.local_surface)
    EMCallSurfaceView localSurface;
    @BindView(R.id.zoom_in_out_btn)
    ImageView zoomInOutBtn;
    @BindView(R.id.dest_user_avatar)
    ImageView destUserAvatar;
    @BindView(R.id.dest_user_name)
    TextView destUserName;
    @BindView(R.id.call_tip)
    TextView callTip;
    @BindView(R.id.hang_up_left_btn)
    ImageButton hangUpLeftBtn;
    @BindView(R.id.hang_up_left_btn_tip)
    TextView hangUpLeftBtnTip;
    @BindView(R.id.hang_up_left_layout)
    RelativeLayout hangUpLeftLayout;
    @BindView(R.id.hang_up_center_btn)
    ImageButton hangUpCenterBtn;
    @BindView(R.id.hang_up_center_layout)
    RelativeLayout hangUpCenterLayout;
    @BindView(R.id.switch_camera_btn)
    ImageButton switchCameraBtn;
    @BindView(R.id.switch_camera_layout)
    RelativeLayout switchCameraLayout;
    @BindView(R.id.call_answer_btn)
    ImageButton callAnswerBtn;
    @BindView(R.id.call_answer_layout)
    RelativeLayout callAnswerLayout;
    @BindView(R.id.chronometer)
    MyChronometer chronometer;
    @BindView(R.id.state_view_text)
    TextView stateViewText;

    private Handler uiHandler;

    private boolean isInCalling;
    boolean isRecording = false;
    private EMVideoCallHelper callHelper;
    private int surfaceState = -1;

    private UserEntity userEntity;

    private boolean endCallTriggerByMe = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (savedInstanceState != null) {
            finish();
            ToastHelper.toast("发生未知错误，请重试");
            return;
        }
        setContentView(R.layout.activity_chat_video_call);
        ButterKnife.bind(this);
        callType = 1;
        getWindow().addFlags(
                WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
                        | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
                        | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);

        initIntent();
        initView();
        initListener();
        uiHandler = new Handler();
    }

    private void initIntent() {
        msgid = UUID.randomUUID().toString();
        isInComingCall = getIntent().getBooleanExtra("isComingCall", false);
        username = getIntent().getStringExtra("username");
    }

    private void initView() {
        userEntity = UserDao.getInstance().query(username);
        if (userEntity == null) {
            doSyncFriend();
        }

        localSurface.setZOrderMediaOverlay(true);
        localSurface.setZOrderOnTop(true);

        // 如果是正在拨打对方视频聊天
        if (!isInComingCall) {

            initOutGoingCallView();

            soundPool = new SoundPool(1, AudioManager.STREAM_RING, 0);
            outgoing = soundPool.load(this, R.raw.outgoing, 1);
            EMClient.getInstance().callManager().setSurfaceView(localSurface, oppositeSurface);
            handler.sendEmptyMessage(MSG_CALL_MAKE_VIDEO);
            handler.postDelayed(new Runnable() {
                public void run() {
                    streamID = playMakeCallSounds();
                }
            }, 300);
        }
        // 如果是接到视频聊天
        else {

            initInComingCallView();
            if (EMClient.getInstance().callManager().getCallState() == EMCallStateChangeListener.CallState.IDLE
                    || EMClient.getInstance().callManager().getCallState() == EMCallStateChangeListener.CallState.DISCONNECTED) {
                // the call has ended
                finish();
                return;
            }
            Uri ringUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE);
            audioManager.setMode(AudioManager.MODE_RINGTONE);
            audioManager.setSpeakerphoneOn(true);
            ringtone = RingtoneManager.getRingtone(this, ringUri);
            ringtone.play();
            EMClient.getInstance().callManager().setSurfaceView(localSurface, oppositeSurface);
        }

        handler.removeCallbacks(timeoutHangup);
        handler.postDelayed(timeoutHangup, Config.MAKE_CALL_TIMEOUT);

        // get instance of call helper, should be called after setSurfaceView was called
        callHelper = EMClient.getInstance().callManager().getVideoCallHelper();
    }

    private void initOutGoingCallView() {

        localSurface.setVisibility(View.GONE);
        zoomInOutBtn.setVisibility(View.GONE);
        destUserAvatar.setVisibility(View.VISIBLE);
        destUserName.setVisibility(View.VISIBLE);
        callTip.setVisibility(View.VISIBLE);
        chronometer.setVisibility(View.GONE);
        hangUpLeftLayout.setVisibility(View.GONE);
        hangUpCenterLayout.setVisibility(View.VISIBLE);
        switchCameraLayout.setVisibility(View.GONE);
        callAnswerLayout.setVisibility(View.GONE);

        initUserInfoView();
        callTip.setText("正在等待对方接受邀请...");
    }

    private void initUserInfoView() {

        if (userEntity == null) {
            GlideUtils.setRoundImageView(this, null, R.drawable.default_avatar, destUserAvatar);
            destUserName.setText(username);
        } else {
            GlideUtils.setRoundImageView(this, userEntity.getAvatar(), R.drawable.default_avatar, destUserAvatar);
            destUserName.setText(AppUtils.getUserName(userEntity));
        }
    }

    private void initInComingCallView() {

        localSurface.setVisibility(View.GONE);
        zoomInOutBtn.setVisibility(View.GONE);
        destUserAvatar.setVisibility(View.VISIBLE);
        destUserName.setVisibility(View.VISIBLE);
        callTip.setVisibility(View.VISIBLE);
        chronometer.setVisibility(View.GONE);
        hangUpLeftLayout.setVisibility(View.VISIBLE);
        hangUpCenterLayout.setVisibility(View.GONE);
        switchCameraLayout.setVisibility(View.GONE);
        callAnswerLayout.setVisibility(View.VISIBLE);
        hangUpLeftBtnTip.setText("拒绝");

        initUserInfoView();
        callTip.setText("邀请你视频聊天");
    }

    private void initAcceptedView() {

        localSurface.setVisibility(View.VISIBLE);
//        zoomInOutBtn.setVisibility(View.VISIBLE);
        zoomInOutBtn.setVisibility(View.GONE);
        destUserAvatar.setVisibility(View.GONE);
        destUserName.setVisibility(View.GONE);
        callTip.setVisibility(View.GONE);
        chronometer.setVisibility(View.VISIBLE);
        hangUpLeftLayout.setVisibility(View.VISIBLE);
        hangUpCenterLayout.setVisibility(View.GONE);
        switchCameraLayout.setVisibility(View.VISIBLE);
        callAnswerLayout.setVisibility(View.GONE);
        hangUpLeftBtnTip.setText("挂断");
    }

    private void initListener() {

        addCallStateListener();

        localSurface.setOnClickListener(view -> doClickLocalSurface());

        hangUpLeftBtn.setOnClickListener(view -> doClickHangUpLeftBtn());

        hangUpCenterBtn.setOnClickListener(view -> doClickHangUpCenterBtn());

        switchCameraBtn.setOnClickListener(view -> doClickSwitchCameraBtn());

        callAnswerBtn.setOnClickListener(view -> doCallAnswerBtn());

    }

    private void doCallAnswerBtn() {
        callAnswerBtn.setEnabled(false);
        openSpeakerOn();
        if (ringtone != null)
            ringtone.stop();

        handler.sendEmptyMessage(MSG_CALL_ANSWER);
        isAnswered = true;
        localSurface.setVisibility(View.VISIBLE);
    }

    private void doClickSwitchCameraBtn() {

        handler.sendEmptyMessage(MSG_CALL_SWITCH_CAMERA);

    }

    private void doClickHangUpCenterBtn() {

        hangUpLeftBtn.setEnabled(false);
        chronometer.stop();
        endCallTriggerByMe = true;
        if (isRecording) {
            callHelper.stopVideoRecord();
        }
        handler.sendEmptyMessage(MSG_CALL_END);

    }

    private void doClickHangUpLeftBtn() {

        if (hangUpLeftBtnTip.getText().toString().equals("拒绝")) {
            isRefused = true;
            hangUpLeftBtn.setEnabled(false);
            handler.sendEmptyMessage(MSG_CALL_REJECT);

        } else if (hangUpLeftBtnTip.getText().toString().equals("挂断")) {
            hangUpLeftBtn.setEnabled(false);
            chronometer.stop();
            endCallTriggerByMe = true;
            if (isRecording) {
                callHelper.stopVideoRecord();
            }
            handler.sendEmptyMessage(MSG_CALL_END);
        }

    }

    private void doClickLocalSurface() {

        changeCallView();
    }

    private void initCallStateConnecting() {

        runOnUiThread(() -> callTip.setText(R.string.Are_connected_to_each_other));
    }

    private void initCallStateConnected() {

        runOnUiThread(() -> {
//             callStateTextView.setText(R.string.have_connected_with);
        });
    }

    private void initCallStateAccepted() {

        surfaceState = 0;
        handler.removeCallbacks(timeoutHangup);
        runOnUiThread(() -> {
            try {
                if (soundPool != null)
                    soundPool.stop(streamID);
            } catch (Exception e) {
            }
            openSpeakerOn();
            isInCalling = true;
            initAcceptedView();
            chronometer.setBase(SystemClock.elapsedRealtime());
            // call durations start
            chronometer.start();
            callingState = CallingState.NORMAL;
        });
    }

    private void initCallStateNetDisconnected() {

        runOnUiThread(() -> {
            stateViewText.setVisibility(View.VISIBLE);
            stateViewText.setText(R.string.network_unavailable);
        });
    }

    private void initCallStateNetUnstable(final EMCallStateChangeListener.CallError error) {

        runOnUiThread(() -> {
            stateViewText.setVisibility(View.VISIBLE);
            if (error == EMCallStateChangeListener.CallError.ERROR_NO_DATA) {
                stateViewText.setText(R.string.no_call_data);
            } else {
                stateViewText.setText(R.string.network_unstable);
            }
        });
    }

    private void initDisconnected(final EMCallStateChangeListener.CallError error) {

        handler.removeCallbacks(timeoutHangup);
        @SuppressWarnings("UnnecessaryLocalVariable") final EMCallStateChangeListener.CallError fError = error;
        runOnUiThread(new Runnable() {
            private void postDelayedCloseMsg() {
                uiHandler.postDelayed(new Runnable() {

                    @Override
                    public void run() {
                        removeCallStateListener();
                        saveCallRecord();
                        ToastHelper.toast("通话结束");
                        finish();
                    }
                }, 200);
            }

            @Override
            public void run() {
                chronometer.stop();
                callDruationText = chronometer.getText().toString();
                String s1 = getResources().getString(R.string.The_other_party_refused_to_accept);
                String s2 = getResources().getString(R.string.Connection_failure);
                String s3 = getResources().getString(R.string.The_other_party_is_not_online);
                String s4 = getResources().getString(R.string.The_other_is_on_the_phone_please);
                String s5 = getResources().getString(R.string.The_other_party_did_not_answer);

                String s6 = getResources().getString(R.string.hang_up);
                String s7 = getResources().getString(R.string.The_other_is_hang_up);
                String s8 = getResources().getString(R.string.did_not_answer);
                String s9 = getResources().getString(R.string.Has_been_cancelled);
                String s10 = getResources().getString(R.string.Refused);

                if (fError == EMCallStateChangeListener.CallError.REJECTED) {
                    callingState = CallingState.BEREFUSED;
                    ToastHelper.toast(s1);

                } else if (fError == EMCallStateChangeListener.CallError.ERROR_TRANSPORT) {
                    ToastHelper.toast(s2);

                } else if (fError == EMCallStateChangeListener.CallError.ERROR_UNAVAILABLE) {
                    callingState = CallingState.OFFLINE;
                    ToastHelper.toast(s3);

                } else if (fError == EMCallStateChangeListener.CallError.ERROR_BUSY) {
                    callingState = CallingState.BUSY;
                    ToastHelper.toast(s4);

                } else if (fError == EMCallStateChangeListener.CallError.ERROR_NORESPONSE) {
                    callingState = CallingState.NO_RESPONSE;
                    ToastHelper.toast(s5);

                } else if (fError == EMCallStateChangeListener.CallError.ERROR_LOCAL_SDK_VERSION_OUTDATED
                        || fError == EMCallStateChangeListener.CallError.ERROR_REMOTE_SDK_VERSION_OUTDATED) {
                    callingState = CallingState.VERSION_NOT_SAME;
                    ToastHelper.toast("通话协议版本不一致");

                } else {
                    if (isRefused) {
                        callingState = CallingState.REFUSED;
                        stateViewText.setText(s10);
                    } else if (isAnswered) {
                        callingState = CallingState.NORMAL;
                        if (endCallTriggerByMe) {
                            //      callStateTextView.setText(s6);
                        } else {
                            stateViewText.setText(s7);
                        }
                    } else {
                        if (isInComingCall) {
                            callingState = CallingState.UNANSWERED;
                            ToastHelper.toast(s8);

                        } else {
                            if (callingState != CallingState.NORMAL) {
                                callingState = CallingState.CANCELLED;
                                ToastHelper.toast(s9);

                            } else {
                                ToastHelper.toast(s6);
                            }
                        }
                    }
                }
                postDelayedCloseMsg();
            }

        });

    }

    /**
     * set call state listener
     */
    private void addCallStateListener() {
        callStateListener = (callState, error) -> {
            switch (callState) {
                case CONNECTING: // is connecting
                    initCallStateConnecting();
                    break;
                case CONNECTED: // connected
                    initCallStateConnected();
                    break;
                case ACCEPTED: // call is accepted
                    initCallStateAccepted();
                    break;
                case NETWORK_DISCONNECTED:
                    initCallStateNetDisconnected();
                    break;
                case NETWORK_UNSTABLE:
                    initCallStateNetUnstable(error);
                    break;
                case NETWORK_NORMAL:
                    runOnUiThread(() -> {
                        stateViewText.setVisibility(View.GONE);
                    });
                    break;
                case VIDEO_PAUSE:
                    break;
                case VIDEO_RESUME:
                    break;
                case VOICE_PAUSE:
                    break;
                case VOICE_RESUME:
                    break;
                case DISCONNECTED: // call is disconnected
                    initDisconnected(error);
                    break;
                default:
                    break;
            }

        };
        EMClient.getInstance().callManager().addCallStateChangeListener(callStateListener);
    }

    void removeCallStateListener() {
        EMClient.getInstance().callManager().removeCallStateChangeListener(callStateListener);
    }

    /**
     * 切换通话界面，这里就是交换本地和远端画面控件设置，以达到通话大小画面的切换
     */
    private void changeCallView() {
        if (surfaceState == 0) {
            surfaceState = 1;
            EMClient.getInstance().callManager().setSurfaceView(oppositeSurface, localSurface);
        } else {
            surfaceState = 0;
            EMClient.getInstance().callManager().setSurfaceView(localSurface, oppositeSurface);
        }
    }

    @Override
    protected void onUserLeaveHint() {
        super.onUserLeaveHint();
        if (isInCalling) {
            try {
                EMClient.getInstance().callManager().pauseVideoTransfer();
            } catch (HyphenateException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (isInCalling) {
            try {
                EMClient.getInstance().callManager().resumeVideoTransfer();
            } catch (HyphenateException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    protected void onDestroy() {
        if (isRecording) {
            callHelper.stopVideoRecord();
            isRecording = false;
        }
        localSurface.getRenderer().dispose();
        localSurface = null;
        oppositeSurface.getRenderer().dispose();
        oppositeSurface = null;
        super.onDestroy();
    }

    @Override
    public void onBackPressed() {
        callDruationText = chronometer.getText().toString();
        super.onBackPressed();
    }

    private void doSyncFriend() {
        NetClient.getInstance()
                .getNetService(UserInterface.class)
                .getUser(AppUtils.getSignParams(username), username)
                .subscribe(new BaseObserver<BaseResponse<UserEntity>>() {
                    @Override
                    public void onSuccess(BaseResponse<UserEntity> response) {
                        userEntity = response.getInfo();
                        UserDao.getInstance().save(userEntity);
                        initUserInfoView();
                    }
                });
    }

}
